<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>大屏渲染</title>
	<link rel="stylesheet" href="../static/layui/css/layui.css">
	<link rel="stylesheet" href="./index.css">
	<style>
		body {
			-moz-user-select: none;
			-webkit-user-select: none;
			-ms-user-select: none;
			user-select: none;
		}

		.context-menu {
			position: absolute;
			background-color: white;
			border: 1px solid #ccc;
			box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
			z-index: 1000;
		}

		.context-menu-item {
			padding: 8px 12px;
			cursor: pointer;
		}

		.context-menu-item:hover {
			background-color: #eee;
		}
	</style>

	<script type="importmap">
    {
        "imports": {
        "three": "../three/v170/three.module.min.js",
        "three/addons/": "../three/v170/"
        }
    }
    </script>
</head>

<body>
	<div class="screen-wrapper">
		<!-- 中间threejs的渲染区域 -->
		<div class="three-box" id="three-box"></div>

		<!-- 标签信息 -->
		<div id="scene-container"></div>
		<div id="labels"></div>

		<div style="position: fixed;left: 0;top: 0;z-index: 9999;display: none;">
			<button id="x_increase">x_增加</button>
			<button id="x_decrease">x_减少</button>
			<button id="y_increase">y_增加</button>
			<button id="y_decrease">y_减少</button>
		</div>

		<div style="position: fixed;left: 0;top: 0;z-index: 9999;">
			<div id="reset_btn">还原</div>
			<div id="add_advice_btn">添加设备</div>
		</div>

		<script src="../static/js/echarts.min-5.5.1.js"></script>
		<script src="../static/layui/layui.js"></script>
		<script type="module">
			import * as THREE from 'three';
			import { CSS2DRenderer, CSS2DObject } from "three/addons/renderers/CSS2DRenderer.js";
			import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from "three/addons/renderers/CSS3DRenderer.js";
			import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
			import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
			import { DragControls } from 'three/addons/controls/DragControls.js';
			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

			layui.use(function () {
				var layer = layui.layer;
				var util = layui.util;
				console.log(`bigScreen.html 118 [layer]`, layer);

				let scene, camera, renderer, controls, isPaused;
				let labelRenderer = null;
				let middle_shebei = {};// 设备--用于位置
				let middle_dengguang = null;// 灯光--射光灯
				const cur_ratio = 0.02;// 缩小的系数
				const raycaster = new THREE.Raycaster();
				const mouse = new THREE.Vector2();
				const texturedPlanes = [];
				let labelsArr = [];// 标签数组
				let renderOrder = 1;// 渲染顺序
				const planeCache = {};// 设备平面缓存

				// 背景数组
				let bgcArr = [
					{
						devicesID: 'bgc_1',// 设备1
						imgURL: './images/souce_05.png',
						width: 1393,
						height: 972,
						label_offset: [0, 0, 0],// 机台偏移量
					},
					{
						devicesID: 'bgc_2',// 设备2
						imgURL: './images/souce_02.png',
						width: 715,
						height: 644,
						label_offset: [0, 0, 0],// 机台偏移量
					}
				];
				// 设备数组
				let devicesArr = [
					{
						devicesID: 'machine_1',// 设备1
						imgURL: './images/souce_01.png',
						width: 107,
						height: 96,
						label_offset: [0.0666999899999869, 0.7156000099999965, 0],// 机台偏移量
					},
					{
						devicesID: 'machine_2',// 设备2
						imgURL: './images/souce_03.png',
						width: 111,
						height: 102,
						label_offset: [-0.3499999999999993, 0.2499999999999988, 0],// 机台偏移量
					}
				];

				// 生成平面
				function createPlane(obj) {
					let imgURL = '';
					let cur_width = 0;
					let cur_height = 0;
					if (obj.devicesID.startsWith('bgc')) {
						const findIndex = bgcArr.findIndex(item => item.devicesID === obj.devicesID);
						imgURL = bgcArr[findIndex].imgURL;
						cur_width = bgcArr[findIndex].width;
						cur_height = bgcArr[findIndex].height;
					} else if (obj.devicesID.startsWith('machine')) {
						const findIndex = devicesArr.findIndex(item => item.devicesID === obj.devicesID);
						imgURL = devicesArr[findIndex].imgURL;
						cur_width = devicesArr[findIndex].width;
						cur_height = devicesArr[findIndex].height;
					}
					const textureLoader = new THREE.TextureLoader();
					const texture = textureLoader.load(imgURL);
					texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
					texture.minFilter = THREE.LinearMipmapLinearFilter;// LinearFilter
					texture.magFilter = THREE.LinearFilter;
					texture.generateMipmaps = true;
					texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;

					const geometry = new THREE.PlaneGeometry(cur_width * cur_ratio, cur_height * cur_ratio); // 根据图片比例设置平面尺寸let


					let opacity = 1;

					if (obj.devicesID.startsWith('machine_1')) {
						opacity = 0.5;
					} else if (obj.devicesID.startsWith('machine_2')) {
						opacity = 1;
					}

					// MeshBasicMaterial 不支持发光效果
					// MeshStandardMaterial 也可以支持更复杂的光照和材质效果
					// MeshPhongMaterial 也可以支持更复杂的光照和材质效果
					const material = new THREE.MeshBasicMaterial({
						map: texture,
						transparent: true, // 允许透明
						opacity: opacity, // 设置不透明度（0.0为完全透明，1.0为完全不透明）
						side: THREE.DoubleSide, // 设置材质为双面
						blending: THREE.NormalBlending, // 使用正常混合模式
						// depthTest: false, // 禁用深度测试
						// depthWrite: false // 禁止写入深度缓冲
						// metalness: 0, // 设置金属度为 0.5
						// alphaTest: 0.1,// 透明度阈值
						// color: 0xffffff, // 设置材质颜色

						roughness: 0.5, // 调整粗糙度
						metalness: 0.2, // 调整金属度
					});
					material.map.colorSpace = THREE.SRGBColorSpace;

					// if (obj.devicesID.startsWith('machine_1')) {
					// 	const highlightColor = new THREE.Color(1, 1, 1); // 红色
					// 	material.color.copy(highlightColor);
					// }

					// 根据渲染顺序设置高亮
					// if (renderOrder % 2 === 0) {
					//   material.emissive = new THREE.Color(0xffffff); // 设置发光颜色
					//   material.emissiveIntensity = 1; // 发光强度
					// } else {
					//   material.emissive = new THREE.Color(0x000000); // 关闭发光
					//   material.emissiveIntensity = 0; // 发光强度
					// }

					const plane = new THREE.Mesh(geometry, material);
					plane.material.depthWrite = false;// 该平面在渲染时会写入深度缓冲区
					const p_x = (obj.position || [])[0] || 0;
					const p_y = (obj.position || [])[1] || 0;
					const p_z = (obj.position || [])[2] || 0;
					plane.position.set(p_x, p_y, p_z);
					// plane.renderOrder = obj.renderOrder || 0; // 设置渲染顺序
					plane.renderOrder = renderOrder; // 设置渲染顺序
					plane.userData = obj;
					renderOrder++;
					scene.add(plane);
					return plane;
				}

				// 添加纹理的函数
				function addTexturedPlane(obj) {
					const plane = createPlane(obj);
					if (obj.labelObj) {
						createLabel({ plane: plane, ...obj });
					}
				}

				function createLabel(obj) {
					// object.geometry.computeBoundingBox(); // 计算包围盒
					const labelObj = obj.labelObj;
					const findIndex = devicesArr.findIndex(item => item.devicesID === obj.devicesID);
					const label_offset = devicesArr[findIndex].label_offset;// 获取偏移量

					const labelDiv = document.createElement('div');
					labelDiv.className = 'label-wrapper';
					labelDiv.innerHTML = `
                <div class="label-bottom"></div>
                <div class="label-line-1"></div>
                <div class="label-line-2"></div>
                <div class="label-content">
                    <h3 class="label-name">${labelObj.name}</h3>
                    <div class="label-item">进程1:xxxx</div>
                    <div class="label-item">进程2:xxxx</div>
                    <div class="label-item">进程3:xxxx</div>
                    <div class="label-item">进程4:xxxx</div>
                </div>
            `;
					document.getElementById('scene-container').appendChild(labelDiv);
					const labelObject = new CSS3DObject(labelDiv);

					const p_x = (obj.position || [])[0] + label_offset[0];
					const p_y = (obj.position || [])[1] + label_offset[1];
					const p_z = (obj.position || [])[2] + label_offset[2];
					labelObject.position.set(p_x, p_y, p_z);
					labelObject.scale.set(cur_ratio, cur_ratio, cur_ratio);
					labelObject.userData = obj;
					middle_shebei['label_' + labelObj.name] = labelObject;
					scene.add(labelObject);

					// 检查labelsArr是否存
					// const find_index = labelsArr.findIndex(item => item.obj.labelObj.uuid === labelObj.uuid);
					// if (find_index === -1) {
					//     labelsArr.push({
					//         labelObject: labelObject,
					//         plane: obj.plane,
					//         obj: obj,
					//     })
					// } else {
					//     labelsArr[find_index] = {
					//         labelObject: labelObject,
					//         plane: obj.plane,
					//         obj: obj,
					//     }
					// }
				}

				function init() {
					scene = new THREE.Scene();
					camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
					camera.rotation.set(0, 0, 0);
					// camera.position.set(10, 10, 10);
					camera.position.set(0, 0, 15);// 正视图
					// camera.lookAt(new THREE.Vector3(0, 0, 0));

					// 创建渲染器
					renderer = new THREE.WebGLRenderer({
						antialias: true,//
						alpha: true,// 设置背景透明
						physicallyCorrectLights: true,// 开启物理光照
						logarithmicDepthBuffer: true,// 开启深度缓存
						powerPreference: "high-performance",// 
					});
					renderer.setSize(window.innerWidth, window.innerHeight);
					renderer.setPixelRatio(window.devicePixelRatio);
					document.getElementById('three-box').appendChild(renderer.domElement);

					// var axesHelper = new THREE.AxesHelper(1000);
					// scene.add(axesHelper);// 创建坐标轴辅助对象

					controls = new OrbitControls(camera, renderer.domElement);// 添加控制器
					controls.enablePan = true;// 添加平移功能

					const ambientLight = new THREE.AmbientLight(0xffffff, 1);
					scene.add(ambientLight);// 添加环境光

					const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
					directionalLight.position.set(15, 15, 0);// 设置光源位置
					scene.add(directionalLight);// 添加平行光

					labelRenderer = new CSS3DRenderer();
					labelRenderer.setSize(window.innerWidth, window.innerHeight);
					labelRenderer.domElement.style.position = 'absolute';
					labelRenderer.domElement.style.top = 0;
					labelRenderer.domElement.style.left = 0;
					labelRenderer.domElement.style.zIndex = 3;
					// 不遮挡canvas和threejs的点击事件;导致使用CSS2DObject添加的HTML标签点击事件无效;
					labelRenderer.domElement.style.pointerEvents = 'none';
					document.body.appendChild(labelRenderer.domElement);

					// 添加场景背景图
					addTexturedPlane({
						devicesID: 'bgc_1',
						position: [0, 0, 0],
					})
					addTexturedPlane({
						devicesID: 'machine_1',
						position: [-10.7, -2.4, 0],
						labelObj: {
							uuid: '1',
							name: '1号机台',
						},
					})
					addTexturedPlane({
						devicesID: 'machine_1',
						position: [-8.8, -3.4, 0],
						labelObj: {
							uuid: '2',
							name: '2号机台',
						},
					})

					addTexturedPlane({
						devicesID: 'machine_2',
						position: [0.908999, -2.3, 0],
						labelObj: {
							uuid: '4',
							name: '4号机台',
						},
					})
					addTexturedPlane({
						devicesID: 'machine_2',
						position: [-1.199999, -0.01222, 0],
						labelObj: {
							uuid: '5',
							name: '5号机台',
						},
					})

					addTexturedPlane({
						devicesID: 'machine_2',
						position: [8.4998, -1.400099, 0],
						labelObj: {
							uuid: '8',
							name: '8号机台',
						},
					})

					// 窗口调整
					window.addEventListener('resize', () => {
						camera.aspect = window.innerWidth / window.innerHeight;
						camera.updateProjectionMatrix();
						renderer.setSize(window.innerWidth, window.innerHeight);
						labelRenderer.setSize(window.innerWidth, window.innerHeight);
					});

					loop();
				}

				// 更新标签位置函数
				function updateLabelPositions() {
					labelsArr.forEach(obj => {
						const vector = new THREE.Vector3();
						obj.plane.getWorldPosition(vector);
						if (obj.labelObject) {
							obj.labelObject.position.copy(vector);
							obj.labelObject.lookAt(camera.position);
						}
					});
				}

				var skip;
				function loop() {
					skip++;
					requestAnimationFrame(loop);
					if (skip < 4) {
						return;
					} else {
						skip = 0;
					}

					// updateLabelPositions();// 更新标签位置
					controls.update(); // 更新控制器
					renderer.render(scene, camera); // 渲染场景
					labelRenderer.render(scene, camera); // 渲染标签
				}

				init();

				// 还原 初始化的场景
				const reset_btn = document.getElementById('reset_btn');
				reset_btn.addEventListener('click', () => {
					controls.reset();
					controls.update(); // 更新控制器
					renderer.render(scene, camera); // 渲染场景
					labelRenderer.render(scene, camera); // 渲染标签
				});

			})
		</script>
</body>

</htm>